package com.imflea.zero.config;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.Iterator;
import java.util.Set;

/**
 * 缓存Redis组件配置类
 */
@Data
@Configuration("masterRedisConfig")
@ConfigurationProperties(prefix = "spring.redis")
@Slf4j
class RedisConfig {


    private String password;

    private String host;

    private Integer port;

    private Integer database;
    //是否开启哨兵模式
    private boolean opensentinel;
    //哨兵模式集群需要使用的参数
    private String mymaster;

    private String redisNodes;

    private String sentinelPassword;

    /**
     * 配置第一个数据源的
     */
    @Bean
    @Primary
    public Object customRedisConfig() {
        if (opensentinel) {
            //哨兵模式
            log.info("--------------------哨兵-----------------");
            RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
            redisSentinelConfiguration.setMaster(mymaster);
            redisSentinelConfiguration.setPassword(password);
            redisSentinelConfiguration.setSentinelPassword(sentinelPassword);
            redisSentinelConfiguration.setDatabase(database);
            appendSentinels(StringUtils.commaDelimitedListToSet(redisNodes), redisSentinelConfiguration);
            return redisSentinelConfiguration;
        } else {
            RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(host, port);
            configuration.setDatabase(database);
            configuration.setPassword(password);
            log.info("--------------------单机-----------------");
            return configuration;
        }

    }

//    @Bean
//    @Primary
//    @ConfigurationProperties(prefix = "spring.redis")
//    public RedisSentinelConfiguration customRedisredisSentinelConfig() {
//        //哨兵模式
//        RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
//        redisSentinelConfiguration.setMaster(mymaster);
//        redisSentinelConfiguration.setPassword(password);
//        redisSentinelConfiguration.setDatabase(database);
//        appendSentinels(StringUtils.commaDelimitedListToSet(redisNodes),redisSentinelConfiguration);
//        return redisSentinelConfiguration;
//    }

    //批量添加哨兵节点的工具方法
    private void appendSentinels(Set<String> hostAndPorts, RedisSentinelConfiguration redisSentinelConfiguration) {
        Iterator var2 = hostAndPorts.iterator();
        while (var2.hasNext()) {
            String hostAndPort = (String) var2.next();
            String[] args = StringUtils.split(hostAndPort, ":");
            Assert.notNull(args, "HostAndPort need to be seperated by  ':'.");
            Assert.isTrue(args.length == 2, "Host and Port String needs to specified as host:port");
            redisSentinelConfiguration.addSentinel(new RedisNode(args[0], Integer.valueOf(args[1])));

        }
    }

    /**
     * 配置lettuce连接池
     */
    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
    public GenericObjectPoolConfig customRedisPool() {
        return new GenericObjectPoolConfig<>();
    }

    /**
     * 配置数据源的连接工厂
     */
    @Bean
    @Primary
    public LettuceConnectionFactory customRedisFactory(@Qualifier("customRedisPool") GenericObjectPoolConfig customRedisPool, @Qualifier("customRedisConfig") Object customRedisStandaloneConfig) {
        LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(customRedisPool).build();
        if (opensentinel) {
            return new LettuceConnectionFactory((RedisSentinelConfiguration) customRedisStandaloneConfig, clientConfiguration);
        } else {
            return new LettuceConnectionFactory((RedisStandaloneConfiguration) customRedisStandaloneConfig, clientConfiguration);
        }
    }

    /**
     * 配置redisTemplate
     */
    @Bean
    @Primary
    public RedisTemplate redisTemplate(@Qualifier("customRedisFactory") RedisConnectionFactory customRedisFactory) {
        return getRedisTemplate(customRedisFactory);
    }

    /**
     * 配置redisTemplate
     */
    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(@Qualifier("customRedisFactory") RedisConnectionFactory customRedisFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(customRedisFactory);
        return template;
    }

    private RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(new GenericToStringSerializer(String.class));
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(new GenericToStringSerializer(String.class));
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

}
